import binascii
import struct
from unicorn import *
from unicorn.x86_const import *
from capstone import *

#注意python3 这里要用这种格式，不然会出奇怪的问题
CHECKSUM_CODE = b"\x55\x8B\xEC\x51\x8B\x55\x0C\xB9\xFF\x00\x00\x00\x89\x4D\xFC\x85\xD2\x74\x51\x53\x8B\x5D\x08\x56\x57\x6A\x14\x58\x66\x8B\x7D\xFC\x3B\xD0\x8B\xF2\x0F\x47\xF0\x2B\xD6\x0F\xB6\x03\x66\x03\xF8\x66\x89\x7D\xFC\x03\x4D\xFC\x43\x83\xEE\x01\x75\xED\x0F\xB6\x45\xFC\x66\xC1\xEF\x08\x66\x03\xC7\x0F\xB7\xC0\x89\x45\xFC\x0F\xB6\xC1\x66\xC1\xE9\x08\x66\x03\xC1\x0F\xB7\xC8\x6A\x14\x58\x85\xD2\x75\xBB\x5F\x5E\x5B\x0F\xB6\x55\xFC\x8B\xC1\xC1\xE1\x08\x25\x00\xFF\x00\x00\x03\xC1\x66\x8B\x4D\xFC\x66\xC1\xE9\x08\x66\x03\xD1\x66\x0B\xC2"
ENCODED_BYTES = b"\x33\xE1\xC4\x99\x11\x06\x81\x16\xF0\x32\x9F\xC4\x91\x17\x06\x81\x14\xF0\x06\x81\x15\xF1\xC4\x91\x1A\x06\x81\x1B\xE2\x06\x81\x18\xF2\x06\x81\x19\xF1\x06\x81\x1E\xF0\xC4\x99\x1F\xC4\x91\x1C\x06\x81\x1D\xE6\x06\x81\x62\xEF\x06\x81\x63\xF2\x06\x81\x60\xE3\xC4\x99\x61\x06\x81\x66\xBC\x06\x81\x67\xE6\x06\x81\x64\xE8\x06\x81\x65\x9D\x06\x81\x6A\xF2\xC4\x99\x6B\x06\x81\x68\xA9\x06\x81\x69\xEF\x06\x81\x6E\xEE\x06\x81\x6F\xAE\x06\x81\x6C\xE3\x06\x81\x6D\xEF\x06\x81\x72\xE9\x06\x81\x73\x7C" 
    
def decode_bytes(i):
    decoded_bytes = b""
    for byte in ENCODED_BYTES:
        decoded_bytes += chr(((ord(byte) ^ i) + 0x22) & 0xFF)
    return decoded_bytes
 
def emulate_checksum(decoded_bytes):
    address = 0x400000
    stack_addr = 0x410000
    dec_bytes_addr = 0x420000

    mu = Uc(UC_ARCH_X86, UC_MODE_32)
    mu.mem_map(address, 2 * 1024 * 1024)
    mu.mem_write(address, CHECKSUM_CODE)
    mu.mem_write(dec_bytes_addr, decoded_bytes)

    mu.reg_write(UC_X86_REG_ESP, stack_addr)
    mu.mem_write(stack_addr + 4, struct.pack('<I', dec_bytes_addr))
    mu.mem_write(stack_addr + 8, struct.pack('<I', 0x79))

    mu.emu_start(address, address + len(CHECKSUM_CODE))
    checksum = mu.reg_read(UC_X86_REG_AX)
    return checksum

for i in range(0, 256):
    decoded_bytes = decode_bytes(i)
    checksum = emulate_checksum(decoded_bytes)
    if checksum == 0xFB5E:
        print ('Checksum matched with byte %X' % i)
        print ('Decoded bytes disassembly:')
        md = Cs(CS_ARCH_X86, CS_MODE_32)
        for j in md.disasm(decoded_bytes, 0x40107C):
            print ("0x%x:\t%s\t%s" % (j.address, j.mnemonic, j.op_str))
        break
